package com.qst.util;

import com.qst.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 订单号生成工具类
 * 格式: RC + 年月日 + 序号（3位）
 * 示例: RC20251001001, RC20251001002, ...
 */
@Component
public class OrderNoGenerator {

    @Autowired
    private OrderRepository orderRepository;

    // 日期格式化器：yyyyMMdd
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    
    // 订单号前缀
    private static final String ORDER_PREFIX = "RC";
    
    // 序号位数
    private static final int SEQUENCE_LENGTH = 3;
    
    // 存储每天的序号计数器，key为日期字符串，value为计数器
    private static final ConcurrentHashMap<String, AtomicInteger> dailyCounters = new ConcurrentHashMap<>();
    
    // 标记计数器是否已初始化
    private static final ConcurrentHashMap<String, Boolean> initialized = new ConcurrentHashMap<>();

    /**
     * 生成订单号
     * @return 订单号，格式：RC20251001001
     */
    public synchronized String generate() {
        // 获取当前日期
        String dateStr = LocalDate.now().format(DATE_FORMATTER);
        
        // 初始化计数器（从数据库获取当天最大序号）
        if (!initialized.getOrDefault(dateStr, false)) {
            initializeCounter(dateStr);
            initialized.put(dateStr, true);
        }
        
        // 获取或创建当天的计数器
        AtomicInteger counter = dailyCounters.computeIfAbsent(dateStr, k -> new AtomicInteger(0));
        
        // 递增计数器并获取序号
        int sequence = counter.incrementAndGet();
        
        // 格式化序号（补齐到指定位数）
        String sequenceStr = String.format("%0" + SEQUENCE_LENGTH + "d", sequence);
        
        // 组合生成订单号
        String orderNo = ORDER_PREFIX + dateStr + sequenceStr;
        
        // 清理旧日期的计数器（避免内存泄漏）
        cleanOldCounters(dateStr);
        
        return orderNo;
    }
    
    /**
     * 从数据库初始化计数器
     * @param dateStr 日期字符串（yyyyMMdd）
     */
    private void initializeCounter(String dateStr) {
        try {
            // 查询当天的订单号前缀
            String orderNoPrefix = ORDER_PREFIX + dateStr;
            
            // 从数据库查询当天最大的订单号
            String maxOrderNo = orderRepository.findMaxOrderNoByPrefix(orderNoPrefix + "%");
            
            if (maxOrderNo != null && maxOrderNo.startsWith(orderNoPrefix)) {
                // 解析出序号
                int maxSequence = parseSequenceFromOrderNo(maxOrderNo);
                if (maxSequence > 0) {
                    // 设置计数器为最大序号
                    dailyCounters.put(dateStr, new AtomicInteger(maxSequence));
                }
            }
        } catch (Exception e) {
            // 如果失败，使用默认值0（计数器已在 computeIfAbsent 中创建）
        }
    }

    /**
     * 生成订单号（带自定义日期）
     * @param date 指定日期
     * @return 订单号
     */
    public synchronized String generateWithDate(LocalDate date) {
        String dateStr = date.format(DATE_FORMATTER);
        
        AtomicInteger counter = dailyCounters.computeIfAbsent(dateStr, k -> new AtomicInteger(0));
        int sequence = counter.incrementAndGet();
        String sequenceStr = String.format("%0" + SEQUENCE_LENGTH + "d", sequence);
        
        return ORDER_PREFIX + dateStr + sequenceStr;
    }

    /**
     * 重置指定日期的计数器
     * @param date 日期
     */
    public void resetCounter(LocalDate date) {
        String dateStr = date.format(DATE_FORMATTER);
        dailyCounters.remove(dateStr);
    }

    /**
     * 重置当天的计数器
     */
    public void resetTodayCounter() {
        resetCounter(LocalDate.now());
    }

    /**
     * 获取当天已生成的订单数量
     * @return 订单数量
     */
    public int getTodayCount() {
        String dateStr = LocalDate.now().format(DATE_FORMATTER);
        AtomicInteger counter = dailyCounters.get(dateStr);
        return counter != null ? counter.get() : 0;
    }

    /**
     * 清理过期的计数器（只保留最近3天的数据）
     * @param currentDateStr 当前日期字符串
     */
    private void cleanOldCounters(String currentDateStr) {
        // 只保留当天的计数器，删除其他日期的
        dailyCounters.keySet().removeIf(dateStr -> !dateStr.equals(currentDateStr));
    }

    /**
     * 解析订单号，获取日期部分
     * @param orderNo 订单号
     * @return 日期字符串（yyyyMMdd），如果格式不正确返回null
     */
    public static String parseDateFromOrderNo(String orderNo) {
        if (orderNo == null || !orderNo.startsWith(ORDER_PREFIX)) {
            return null;
        }
        
        int prefixLength = ORDER_PREFIX.length();
        if (orderNo.length() < prefixLength + 8) {
            return null;
        }
        
        return orderNo.substring(prefixLength, prefixLength + 8);
    }

    /**
     * 解析订单号，获取序号部分
     * @param orderNo 订单号
     * @return 序号，如果格式不正确返回-1
     */
    public static int parseSequenceFromOrderNo(String orderNo) {
        if (orderNo == null || !orderNo.startsWith(ORDER_PREFIX)) {
            return -1;
        }
        
        int prefixLength = ORDER_PREFIX.length();
        int expectedLength = prefixLength + 8 + SEQUENCE_LENGTH;
        
        if (orderNo.length() != expectedLength) {
            return -1;
        }
        
        try {
            String sequenceStr = orderNo.substring(prefixLength + 8);
            return Integer.parseInt(sequenceStr);
        } catch (NumberFormatException e) {
            return -1;
        }
    }

    /**
     * 验证订单号格式是否正确
     * @param orderNo 订单号
     * @return true-格式正确，false-格式错误
     */
    public static boolean isValidOrderNo(String orderNo) {
        if (orderNo == null || orderNo.isEmpty()) {
            return false;
        }
        
        // 检查前缀
        if (!orderNo.startsWith(ORDER_PREFIX)) {
            return false;
        }
        
        // 检查长度：RC(2) + 日期(8) + 序号(3) = 13
        int expectedLength = ORDER_PREFIX.length() + 8 + SEQUENCE_LENGTH;
        if (orderNo.length() != expectedLength) {
            return false;
        }
        
        // 检查日期部分是否为数字
        String dateStr = orderNo.substring(ORDER_PREFIX.length(), ORDER_PREFIX.length() + 8);
        if (!dateStr.matches("\\d{8}")) {
            return false;
        }
        
        // 检查序号部分是否为数字
        String sequenceStr = orderNo.substring(ORDER_PREFIX.length() + 8);
        if (!sequenceStr.matches("\\d{" + SEQUENCE_LENGTH + "}")) {
            return false;
        }
        
        // 验证日期是否合法
        try {
            LocalDate.parse(dateStr, DATE_FORMATTER);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

